import { useState, useEffect, useMemo } from "react";
import type { FormProps, FieldBaseType } from "./type";
import { isUndefined } from "@ct0/functions";
import validator from "./validator";

const emptyDeps: Array<undefined> = [];

export default function useFormView<T extends FieldBaseType>(
  propsFields: (() => Array<T>) | Array<T>,
  deps: Array<any> = emptyDeps
): [
  FormProps<T>,
  boolean,
  Record<string, any>,
  Array<{ key: string; value: any }>
] {
  const fields = useMemo(() => {
    return typeof propsFields == "function" ? propsFields() : propsFields;
  }, deps);

  const onChange = (values: any = [], isValid: boolean) => {
    for (let i = 0; i < fields.length; i++) {
      fields[i].value = values[i];
    }
    setFormAndData({
      form: { fields, onChange },
      isValid,
      cachedValues: getFieldsValues(fields),
    });
  };

  const getV = (i: T) => (isUndefined(i.value) ? i.defaultValue : i.value);

  const getFieldsValues = (fields: Array<T>) =>
    fields.map((i) => ({ key: i.key, value: getV(i) }));

  const getIsAllValid = () => {
    return fields
      .map((i) => validator(i, getV(i))[0])
      .reduce((r, i) => r && i, true);
  };

  const [formAndData, setFormAndData] = useState(() => {
    return {
      form: { fields, onChange },
      isValid: getIsAllValid(),
      cachedValues: getFieldsValues(fields),
    };
  });

  useEffect(() => {
    const isValid = getIsAllValid();
    /**
     * 当 fields 改变的时候，需要判断每个 field 中的 value 是否为 undefined
     * 如果是，则需要把 values 当前的值补充进去, 补充的时候有按顺序补充和按key补充两种分案
     * 按顺序补充时，如果 fields 的数量发生变化，就补充不进去了
     * 按key补充是，如果 key 重名，就会被覆盖
     * 这里选择了使用按 key 补充
     */
    for (const f of fields) {
      if (isUndefined(f.value)) {
        for (const v of formAndData.cachedValues)
          if (f.key == v.key) f.value = v.value;
      }
    }
    setFormAndData({
      form: { fields, onChange },
      isValid,
      cachedValues: getFieldsValues(fields),
    });
  }, [fields]);

  const kvValue: Record<string, any> = {};
  for (let i = 0; i < formAndData.form.fields.length; i++)
    kvValue[formAndData.form.fields[i].key] = getV(formAndData.form.fields[i]);

  return [
    formAndData.form,
    formAndData.isValid,
    kvValue,
    formAndData.cachedValues,
  ];
}
